package com.t3.client
{
	import com.t3.animation.*;
	import com.t3.anistory.*;
	import com.t3.display.*;
	import com.t3.events.StoryEvent;
	import com.t3.fx.*;
	import com.t3.tuio.*;
	import com.t3.util.*;
	
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	
	import flash.display.Sprite;
	import flash.events.KeyboardEvent;
	import flash.geom.Point;
	import flash.utils.Dictionary;
	import flash.net.registerClassAlias;
	import flash.utils.Timer;

	public class T3Client extends StageObject implements ITUIOListener
	{
		public static const _width:uint = 1280;
		public static const _height:uint = 1024;
		public static const _framerate:uint = 100;
		
		public static var cursors:Dictionary = new Dictionary();
		public static var liveObjects:Dictionary = new Dictionary();
		public static var objects:Dictionary = new Dictionary();
		
		public static var waslijn:Waslijn;
		public static var client:T3Client;
		
		private var currentStory:AniStory;
		private var storyLayer:Sprite = new Sprite();
		private var objectLayer:Sprite = new Sprite();
		
		private var _timeOut:Timer = new Timer( 1500, 1 );
		
		/**
		 *  T3Client
		 *  Hoofdklasse van het programma, rest wordt via deze klasse opgebouwd. 
		 */
		public function T3Client()
		{
			client = this;
			
			waslijn = new Waslijn();
			waslijn.stageLoc = new Point( 10, waslijn.currentStory.x + waslijn.currentStory.height + 315 );
			waslijn.addEventListener( StoryEvent.STORY_CHANGED, changeStory );
			currentStory = waslijn.currentStory;
			
			this.addChild( storyLayer );
			this.addChild( objectLayer );
			
			storyLayer.addChild( currentStory );
			objectLayer.addChild( waslijn );
			
			var tuioClient:TUIOClient = new TUIOClient( this );
		}
		
		/**
		 * Vervangt de huidige story voor een nieuwe story. 
		 * Keylisteners zijn voor tijdelijk, om te testen en te debuggen.
		 */
		public function changeStory( event:StoryEvent ):void
		{	
			if( currentStory != event.story )
			{
				startTimeout();			
				stage.removeEventListener( KeyboardEvent.KEY_DOWN, currentStory.keyDown );
				remove( currentStory, storyLayer );
				currentStory = event.story;
				stage.addEventListener( KeyboardEvent.KEY_DOWN, currentStory.keyDown );
				storyLayer.addChild( currentStory );
			}		
		}
		
		/**
		 *  Timeout nodig voor het stabiel laten lopen van de applicatie 
		 */
		public function startTimeout( event:KeyboardEvent = null ):void
		{
			_timeOut.reset();
			_timeOut.start();
		}
		
		/**
		 *  Als het addobject event binnenkomt, dan wordt er afhankelijk van de fiducial ID het object bijgezocht en weergegeven.
		 *  Er zijn drie objecten:
		 *  CharArea: het letterblokje
		 *  WoordArea: het woordenboekje
		 *  Microfoon ( ID 5 )
 		 */
		public function addObject( event:TUIOEvent ):void
		{
			var obj:TUIOObject = objects[ event.f_id ];
			
			if( obj == null )
			{
				switch( event.f_id )
				{
					case CharArea.ID: obj = objects[ event.f_id ] = new CharArea( event ); break;
					case WoordArea.ID: obj = objects[ WoordArea.ID ] = new WoordArea( event ); break;
					case 5: currentStory.startRecord(); obj = new TUIOObject( event ); break;
					default: obj = new TUIOObject( event ); break;
				}
			}
			
			if( obj.isActive && obj.visible )
			{
				startTimeout();
			}
			
			liveObjects[ event.s_id ] = obj;
			objectLayer.addChild( obj );
			obj.addToStage();
			obj.update( event );
			
			// Er wordt gekeken of de timeout van obj niet is verlopen, tegen knipperen.
			if( obj.persistent )
			{
				obj.addEventListener( TUIOEvent.REMOVE_TUIO_OBJ, removeFromStage );
			}
		}
		
		
		public function removeObject( event:TUIOEvent ):void
		{
			if( objects[ event.f_id ] != null && objects[ event.f_id ].persistent )
			{
				objects[ event.f_id ].removed();
			}
			else
			{			
				remove( liveObjects[ event.s_id ], objectLayer );
			}
			
			if ( event.f_id == 5 )
			{
				currentStory.stopRecord();
			}
			
			liveObjects[ event.s_id ] = null;
			delete( liveObjects[ event.s_id ] );
		}
		
		public function removeFromStage( event:TUIOEvent ):void
		{
			remove( event.point, objectLayer );
		}
		
		public function updateObject( event:TUIOEvent ):void
		{
			liveObjects[ event.s_id ].update( event );
		}
		
		public function refresh( event:TUIOEvent ):void {}
		
		public function addCursor( event:TUIOEvent ):void
		{
			if( !_timeOut.running )
			{
				var dob:DraggableObject = dragObject( event );
				var cursor:TUIOCursor = dob != null ? new TUIOCursor( event, dob ) : new TUIOTrail( event );
				cursor.update( event );
				
				event.data.point = cursor;
				
				var ca:CharArea = objects[ CharArea.ID ];
				var wa:WoordArea = objects[ WoordArea.ID ];
							
				cursors[ event.s_id ] = cursor;
				
				if( !( ( ca != null && ca.visible || wa != null && wa.visible ) && cursor is TUIOTrail ) )
				{
					this.dispatchEvent( new TUIOEvent( TUIOEvent.ADD_TUIO_CUR, event.data ) );
				}
			}
		}
		
		public function updateCursor( event:TUIOEvent ):void
		{
			if( cursors[ event.s_id  ] != null )
			{
				cursors[ event.s_id ].update( event );
			}
		}
		
		public function removeCursor( event:TUIOEvent ):void
		{
			if( cursors[ event.s_id ] != null)
			{
				cursors[ event.s_id ].remove();	
				cursors[ event.s_id ] = null;
				delete( cursors[ event.s_id ] );
			}
		}
		
		private function remove( dob:DisplayObject, doc:DisplayObjectContainer ):void
		{
			if( doc.contains( dob ) )
			{
				doc.removeChild( dob );
			}
		}
		
		private function dragObject( event:TUIOEvent ):DraggableObject
		{
			if ( objects[ CharArea.ID ] != null && objects[ CharArea.ID ].visible )
			{
				for each( var dob:DraggableObject in objects[ CharArea.ID ].letters )
				{				
					if( dob.hitTestPoint( event.xStage, event.yStage ) )
					{
						return dob;
					}
				}
			}
			
			if( objects[ WoordArea.ID ] != null && objects[ WoordArea.ID ].visible ) 
			{
				for each( var dobw:DraggableObject in objects[ WoordArea.ID ].currentWoorden )
				{				
					if( dobw.hitTestPoint( event.xStage, event.yStage ) )
					{
						return dobw;
					}
				}
			}
			
			for each( var dobc:DraggableObject in waslijn.currentStory.notebook.objects )
			{				
				if( dobc.hitTestPoint( event.xStage, event.yStage ) )
				{
					return dobc;
				}
			}
			
			for each( var dobs:DraggableObject in waslijn.pages )
			{
				if( dobs.hitTestPoint( event.xStage, event.yStage ) )
				{
					return dobs;
				}
			}
			
			if( waslijn.playButton.hitTestPoint( event.xStage, event.yStage ) )
			{
				return waslijn.playButton;
			}
			
			return null;
		}
	}
}